home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac100% 1998 November
/
MAC100-1998-11.ISO.7z
/
MAC100-1998-11.ISO
/
オンラインソフト定点観測
/
ユーティリティ
/
Mops 3.2.sea
/
Mops 3.2
/
Mops ƒ
/
Struct
< prev
next >
Wrap
Text File
|
1998-05-02
|
26KB
|
1,074 lines
¥ Standard data structure classes
¥ May 91 Added Longword
¥ June 91 Reimplemented ordered-col etc. using multiple inheritance
¥ May 92 Added obj_array
¥ July 92 Fixed OBJ: ObjHandle to use NPTR: instead of PTR:
¥ HandleArray now inherits from Obj_array.
¥ Dec 92 Replaced UGET: in Int and Byte with new classes UINT and UBYTE.
cr .( loading Struct...)
:class LONGWORD super{ object } ¥ Generic superclass for var, handle etc.
4 bytes data
:m CLEAR: inline{ 0 obj !} 0 ^base ! ;m
:m GET: inline{ obj @} ^base @ ;m
:m PUT: inline{ obj !} ^base ! ;m
:m ->: inline{ @ obj !} chksame @ put: self ;m
:m PRINT: ^base @ . ;m
:m CLASSINIT: clear: self ;m
;class
:class VAR super{ longword }
:m +: inline{ obj +!} ^base +! ;m
:m -: inline{ obj -!} ^base -! ;m
;class
:class INT super{ object }
2 bytes data
:m CLEAR: inline{ 0 obj w!} 0 ^base w! ;m
:m GET: inline{ obj w@x} ^base w@x ;m
:m PUT: inline{ obj w!} ^base w! ;m
:m +: inline{ obj w+!} ^base w+! ;m
:m -: inline{ obj w-!} ^base w-! ;m
:m ->: inline{ w@ obj w!}
chksame w@ put: self ;m
:m INT: ^base w@ makeint ;m ¥ return as toolbox int
:m PRINT: ^base w@x . ;m
:m CLASSINIT: clear: self ;m
;class
:class UINT super{ int }
:m GET: inline{ obj w@} ^base w@ ;m
:m PRINT: ^base w@ . ;m
;class
:class BYTE super{ object }
1 bytes data
:m CLEAR: inline{ 0 obj c!} 0 ^base c! ;m
:m GET: inline{ obj c@x} ^base c@x ;m
:m PUT: inline{ obj c!} ^base c! ;m
:m +: inline{ ^base c@ + ^base c!} ;m
:m -: inline{ negate ^base c@ + ^base c!} ;m
:m ->: inline{ c@ obj c!} chksame c@ put: self ;m
:m PRINT: ^base c@x . ;m
:m CLASSINIT: clear: self ;m
;class
:class UBYTE super{ byte }
:m GET: inline{ obj c@} ^base c@ ;m
:m PRINT: ^base c@ . ;m
;class
:class BOOL super{ byte }
:m PUT: inline{ 0<> obj c!} 0<> ^base c! ;m
:m SET: inline{ true obj c!} true ^base c! ;m
¥ note - CLEAR: is defined in the superclass Byte
:m NOT: inline{ obj c@ not obj c!} ^base c@ not ^base c! ;m
:m PRINT: get: self IF ." true" ELSE ." false" THEN ;m
;class
¥ Handle class can store handles to relocatable heap blocks.
¥ It would be nice to store the length too, but this class is used
¥ for handles in toolbox records so we can't. Not here at least.
0 value RELCNT ¥ For testing - counts release: msgs
¥ to make sure we're releasing everything
:class HANDLE super{ longword }
:m PTR: ¥ Dereferences handle to get pointer. Trap if nil.
inline{ obj @ @} ^base @ @ ;m
:m NPTR: ¥ Dereferences handle and masks with SAmask so we can
¥ use the pointer numerically.
^base @ @ SAmask and ;m
:m RELEASE: ¥ Deallocates the heap block, if allocated.
1 ++> relCnt killH ;m
:m CLEAR: nilH ^base ! ;m ¥ We hope we know what we're doing.
:m NIL?: ¥ ( -- b )
get: self nilH = ;m
:m SETSIZE: ¥ ( size -- }
setHsz 0= ?error 166 ;m
:m SIZE: ¥ ( -- size ) Gets current size.
getHSz ;m
:m NEW: ¥ ( size -- )
newH 0= ?error 166 ;m
:m LOCK: lok ;m
:m UNLOCK: unlok ;m
:m GETSTATE: ( -- state ) HgetSt ;m
:m SETSTATE: ( state -- ) HsetSt ;m
:m LOCKED?: ( -- b ) HgetSt $ 80 and 0<> ;m
:m MOVEHI: MvHHi drop ( errors don't really matter here ) ;m
:m ->: ¥ ( ^hdl -- ) Copies passed-in handle's heap data to self.
chkSame copyH ?error 167 ;m
:m PRINT:
& $ emit ^base @ u.h ;m ¥ We assume a print: of a handle is more
¥ useful in hex.
:m CLASSINIT: clear: self ;m ¥ Initially nil
;class
¥ OBJHANDLE is a handle that points to an object in the heap.
:class OBJHANDLE super{ handle }
:m OBJ: moveHi: self lock: self nptr: self >obj ;m
¥ Note: if we're going to bind to a heap-based object,
¥ the handle MUST be locked while we do so - anything
¥ may happen before the method returns!! Thus we make the
¥ obj: method do a moveHi and lock. But remember to unlock
¥ the handle eventually! (Unless you're releasing it, of course.)
:m NEWOBJ: ( #els ) { ^class -- }
¥ Usage: 5 ['] someClass newObj: someHndl
^class cl>len 8 + new: self
^class obj: self make_obj unlock: self ;m
:m RELEASEOBJ:
nil?: self ?EXIT
obj: self release: [] release: super ;m
:m RELEASE: releaseObj: self ;m ¥ Standard destructor name.
¥ Note: we define both release: and releaseObj: so that in classes
¥ HandleArray and HandleList we can distinguish between releasing the
¥ current object and releasing the whole lot. Release: is of course
¥ overridden in those two classes to release the entire structure.
:m PRINT:
print: super 4 spaces ." object: "
nil?: self
if ." (none)"
else print: [ obj: self ] unlock: self
then ;m
:m DUMP:
dump: super cr
." object: "
nil?: self
if ." (none)"
else dump: [ obj: self ] unlock: self
then ;m
;class
:class PTR super{ longword }
:m RELEASE: ¥ Deallocates the heap block, if allocated.
killP ;m
:m NEW: ( len -- ) newP 0= ?error 121 ;m
:m NIL?: ( -- b ) ^base @ nilP = ;m
:m CLEAR: nilP ^base ! ;m ¥ We hope we know what we're doing.
:m CLASSINIT: clear: self ;m ¥ Initially nil
;class
¥ DICADDR is a relocatable dictionary address class - use to store
¥ non-executable dictionary addresses.
:class DICADDR super{ longword }
:m GET: ^base @abs ;m
:m PUT: ^base reloc! ;m
:m PRINT: get: self .id ;m
:m CLASSINIT: ['] null put: self ;m
;class
¥ X-ADDR is an executable dictionary address class. The only significant
¥ difference to DicAddr is that there is an Exec: method.
¥ But if we ever have to separate code and data, having a separate class
¥ could prove very useful. An x-addr is the same as a Mops execution token.
:class X-ADDR super{ object }
4 bytes data
:m EXEC: inline{ obj ex} ^base @abs execute ;m
:m GET: ^base @abs ;m
:m PUT: ^base reloc! ;m
:m CLASSINIT: ['] null put: self ;m
;class
¥ ============= Arrays ===============
: ?#XTS ¥ ( n1 n2 -- ) Used to check that the right
¥ number of stacked cfas is being passed in.
<> ?error 171 ; ¥ "Wrong number of cfas"
¥ Class INDEXED-OBJ is the generic superclass for all arrays. Here we define
¥ the general indexed methods, which apply regardless of indexed width.
:class INDEXED-OBJ super{ object }
:m ^ELEM: ^elem ;m
:m LIMIT: limit ;m
:m WIDTH: idxbase 6 - w@ ;m
:m IXADDR: idxbase ;m
:m CLEARX: ¥ Erases indexed area.
idxbase limit width: self * erase ;m
:m CLASSINIT: clearX: self ;m
;class
¥ ARRAY is the basic 4-byte cell array.
:class ARRAY super{ indexed-obj } 4 indexed
:m AT: ( index -- n ) inline{ ix @} ^elem4 @ ;m
:m TO: ( n index -- ) inline{ ix !} ^elem4 ! ;m
:m +TO: ( n index -- ) inline{ ix +!} ^elem4 +! ;m
:m -TO: ( n index -- ) inline{ ix -!} ^elem4 -! ;m
:m ^ELEM: ( idx -- addr ) inline{ ix} ^elem4 ;m
:m FILL: ¥ ( value -- ) Fills all elements with value.
idxbase limit 4* bounds
?do dup i ! 4 +loop drop ;m
:m WIDTH: 4 ;m ¥ Faster than the default in Indexed-obj.
:m GETELEM: ¥ ( addr -- n ) Fetches one element at addr - saves indexing
¥ step if addr is known.
@ ;m
;class
¥ X-ARRAY can execute its elements.
:class X-ARRAY super{ array }
:m TO: ( index -- ) ^elem: super reloc! ;m
:m EXEC: ( index -- )
inline{ ix ex} ^elem: self @abs execute ;m
:m FILL: ¥ ( xt -- )
limit nif drop exit then ¥ Out if no elements
idxbase tuck reloc! @ fill: super ;m
:m PUT: ¥ ( xt0 ... xt(N-1) N -- )
limit 0EXIT ¥ Out if no elements
false -> relocChk? ¥ May get used in instantiating exported objs
limit ?#xts
idxbase dup limit 1- 4* +
do i reloc! -4 +loop
true -> relocChk? ;m
:m ACTIONS: ¥ A synonym for put:. A more appropriate name to use in
¥ sub-classes such as dialogs.
put: self ;m
private
:m PrintNxts: ¥ ( n -- )
0 ?do i ^elem: self @abs cr .id loop ;m
public
:m PRINT: limit printNxts: self ;m
:m CLASSINIT: ['] null fill: self ;m
;class
¥ SEQUENCE is a generic superclass for classes which have multiple items which
¥ frequently need to be looked at in sequence. At present the main function of
¥ Sequence is to implement the EACH: method, which makes it very simple to
¥ deal with each element. The usage is
¥
¥ BEGIN each: <obj> WHILE <do something to the element> REPEAT
¥
¥ Sequence can be multiply inherited with any class which implements the
¥ FIRST?: and NEXT?: methods. The actual implementation details are quite
¥ irrelevant, as long as these methods are supported.
¥ But note that any class using Sequence should not appear in a record, since
¥ we must late bind to self, so a class pointer must be present.
:class SEQUENCE super{ object } general
record
{ var NXT_XT
var ^SELF
}
:m EACH: ¥ ( -- (varies) T | -- F )
get: nxt_xt
NIF ¥ First time in:
first?: [self] 0dup 0EXIT
self bind_with next?: ¥ Late-bind to next?: and cache
put: nxt_xt put: ^self ¥ the xt for the loop
true ¥ Yes, we've got the 1st element
ELSE ¥ Subsequent time in:
get: ^self get: nxt_xt ex-method ¥ Call next?: method (cached)
IF true ELSE clear: nxt_xt false THEN
THEN ;m
:m UNEACH: ¥ Use to terminate an EACH: loop before the end.
clear: nxt_xt ;m
;class
0 value LASTSUP
0 value LASTSUPADDR
: REMOVELASTSUPER { ^class ¥ infa -- }
^class ifa displace -> infa
BEGIN infa @ 0> NWHILE infa ^nextivar -> infa
REPEAT
BEGIN
4 ++> infa
infa @
NUNTIL
4 --> infa
infa -> lastSupAddr
infa @ -> lastSup
0 infa ! ;
: RESTORELASTSUPER
lastSup lastSupAddr ! ;
(*
OBJ_ARRAY is a generic superclass which makes it easy to generate an array
of objects of a given class. Just define a new class which multiply
inherits from the given class (or classes) and OBJ_ARRAY (which must come
last). This will add an indexed section to each object of the new class,
with elements wide enough to contain objects of the original class. Then
SELECT: "switches in" the selected element to be the "current" element,
and all the normal methods of the class can then be used.
The implementation is general rather than brilliantly fast. If switching
between elements is really a performance concern, you could override
SELECT: - especially if you know the element width. But note, we do
assume the elements are aligned.
*)
:class OBJ_ARRAY super{ indexed-obj sequence } 32767 indexed
¥ The 32767 signals that the real indexed width is to be
¥ taken from the other superclass(es).
record
{ int CURRENT }
:m CURRENT:
get: current ;m
:m SELECT: { idx ¥ datalen slf -- }
idx get: current = ?EXIT ¥ out if nothing to do
width: self -> datalen self -> slf ¥ set up
slf get: current ^elem datalen aligned_move ¥ switch out previous
idx ^elem ¥ note: will give an error if out of range
¥ - so we do it before we store in current
slf datalen aligned_move ¥ switch in new
idx put: current ;m
:m FIRST?:
limit NIF false EXIT THEN
0 select: self true ;m
:m NEXT?:
get: current 1+ limit >= IF false EXIT THEN
get: current 1+ select: self true ;m
:m PRINTALL: ¥ Sends PRINT: to all elements
get: current
BEGIN each: self WHILE print: [self] REPEAT
select: self ;m
(*
CLASSINIT: needs to initialize all the elements. Element 0 has been
initialized already, by the time we get classinit: sent here, since we're
the last superclass. We could select each element and send deep_classinit:,
but it's a bit tricky getting the right class to use. Instead we'll just
copy element 0 to the other elements, which will usually be good enough.
*)
:m CLASSINIT: { ¥ dln slf -- }
width: self -> dln self -> slf ¥ set up
limit 1 ¥ note: elt 0 has had classinit: already!
?DO
slf i ^elem dln aligned_move
LOOP
;m
;class
(* LARGE_OBJ_ARRAY is similar in usage to OBJ_ARRAY, but is faster
if the elements are large (>20 bytes or so).
When we select an element, we don't move it, but instead update
an offset to the current element, which we keep in the ivar xdispl.
When we call a method in the selected element, ^base is set to
the element, naturally. This means that we need a ^class offset
at the start of each element, which we didn't need in obj_array.
So we allocate two extra bytes for each element, and set up all
the ^class offsets at classinit: time.
*)
:class LARGE_OBJ_ARRAY super{ indexed-obj sequence } 32766 indexed
¥ The 32766 signals that the real indexed width is to be
¥ taken from the other superclass(es).
record
{ var xdispl
int CURRENT }
:m CURRENT:
get: current ;m
:m SELECT: { idx ¥ datalen slf -- }
idx get: current = ?EXIT ¥ out if nothing to do
idx ^elem 2+ ¥ 2+ to step over ^class offset
addr: xdispl displ!
idx put: current ;m
:m FIRST?:
limit NIF false EXIT THEN
0 select: self true ;m
:m NEXT?:
get: current 1+ limit >= IF false EXIT THEN
get: current 1+ select: self true ;m
:m PRINTALL: ¥ Sends PRINT: to all elements
get: current
BEGIN each: self WHILE print: [self] REPEAT
select: self ;m
(*
CLASSINIT: needs to initialize all the elements. The base object has been
set up already, by the time we get classinit: sent here, since we're
the last superclass, but it isn't one of the elements! So analogously
to what we do in OBJ_ARRAY, we copy the base object to all the elements
(INCLUDING elt zero here!).
*)
:m CLASSINIT: { ¥ dln slf addr ^obj -- }
^base 2- wdisplace -> ^obj
width: self -> dln self -> slf ¥ set up
limit 0
?DO
i ^elem -> addr
^obj addr wdispl!
slf addr 2+ dln aligned_move
LOOP
¥ now we set up the xdispl ivar, so elt 0 is initially selected.
idxBase 2+ addr: xdispl displ!
;m
;class
¥ (PHlist) is a superclass for HandleList and PtrList, mainly aimed at
¥ factoring out common code. It's really only meant for internal use.
:class (PHlist) super{ sequence }
record
{ handle THELIST
var SIZE
var POS
}
private
:m (SEL): ¥ ( n -- ) n is offset into theList, NOT an index.
self @ ptr: theList get: pos + ! ¥ switch out previous
put: pos
ptr: theList get: pos + @ self ! ¥ switch in new
;m
public
:m ADD: { addMe ¥ whr ^class -- }
get: size -> whr
whr
NIF nil?: theList
IF 80 new: theList ¥ Give it room to play with
ELSE 80 setsize: theList
THEN
THEN
whr cell+ dup setsize: theList put: size
whr (sel): self
addMe self !
;m
:m REMOVE: { ¥ whr cnt -- } ¥ Completely removes the current element.
ptr: theList get: pos + -> whr
1cell -: size get: size get: pos - -> cnt
cnt IF whr cell+ whr cnt move THEN
¥ note: can't use aligned_move since it's a move down,
¥ and overlaps
get: pos cell- 0 max put: pos
ptr: theList get: pos + @ self ! ¥ switch in new current elt
get: size NIF release: theList THEN ;m
:m SELECT: ¥ ( n -- )
4* 0 get: size cell- within? not ?error 134
(sel): self ;m
:m SELECTLAST:
get: size cell- (sel): self ;m
:m CURRENT: get: pos 4/ ;m
:m SIZE: get: size 4/ ;m
¥ The next two methods are needed by EACH:, but may be called directly as well.
¥ Note that NEXT?: ASSUMES that the list is allocated in the heap and that a
¥ valid element is selected as the current element. EACH: ensures this,
¥ since if FIRST?: returns false, NEXT?: is never called. But if you call
¥ it directly, make sure this condition holds.
:m FIRST?: ¥ ( -- n T | -- F )
nil?: theList IF false EXIT THEN
0 (sel): self self @ true ;m
:m NEXT?: { ¥ nxt -- n T | -- F }
get: pos cell+ -> nxt
nxt get: size >= IF false EXIT THEN
nxt (sel): self self @ true ;m
:m DUMPALL:
nil?: theList IF ." (not open)" EXIT THEN
dump: super cr ." current: " current: self dup .
cr ." elements: " cr
BEGIN each: [self] WHILE dump: [self] REPEAT
select: self ;m
:m PRINTALL:
nil?: theList IF ." (not open)" EXIT THEN
get: pos
BEGIN each: self WHILE print: [self] cr REPEAT
(sel): self ;m
;class
¥ HANDLEARRAY and HANDLELIST are for the implementation of collections
¥ of heap-based objects. HandleArray has normal array properties, and
¥ thus a definite length. HandleList, however, allows the number of
¥ elements to grow arbitrarily large. Use HandleList if you need an
¥ indefinite number of elements, and if indexing isn't so important.
¥ HandleArray also includes methods to allow the array to be used as a
¥ stack - needed for FileList.
:class HANDLEARRAY super{ objHandle array obj_array }
record
{ int size }
:m SIZE: get: size ;m
:m SETSIZE: put: size ;m
:m RELEASE:
get: size 0 ?DO
i select: self releaseObj: self
LOOP ;m
:m PUSH: ¥ ( hdl -- )
get: size limit >= ?error 137
get: size select: self 1 +: size
put: super ;m
private
:m (TOP):
get: size dup
IF 1- select: self
ELSE drop clear: current
THEN ;m
public
:m TOP:
get: size 0= ?error 136 (top): self ;m
:m DROP:
get: size dup 0= ?error 136
1- select: self releaseObj: self
1 -: size (top): self ;m
:m PUSHNEWOBJ:
0 push: self newObj: self ;m
:m CLEARX: nilH fill: self ;m
:m CLASSINIT: clearX: self clear: self ;m
;class
¥ HANDLELIST allows the implementation of a list of heap-based objects.
¥ Unlike HANDLEARRAY, the list can be of indefinite length. We use a heap
¥ block to store the handles to the objects contiguously, rather than have
¥ a separate block for each handle and link them together. This saves on
¥ memory overhead and reduces the number of memory manager calls. It also
¥ reflects the assumption that insertions and deletions into the middle of
¥ the list will be infrequent, as these could be more inefficient than with
¥ a linked scheme. We expect that elements will normally be added to the
¥ end, and probably not removed at all, or not very often.
:class HANDLELIST super{ objHandle (PHlist) }
¥ FIRST?: and NEXT?:, needed for the EACH: construction, are overridden here
¥ since if the next element exists we return the object address as well as
¥ the True. We also need to unlock the previous objHandle when we step
¥ to the next one.
:m SIZE: ¥ We're overriding here since objHandle has a size: method
¥ which isn't really useful here
size: super> (PHlist) ;m
:m FIRST?: ¥ ( -- ^obj T | -- F )
first?: super NIF false EXIT THEN
drop obj: self true ;m
:m NEXT?: { ¥ nxt -- ^obj T | -- F }
unlock: super
next?: super NIF false EXIT THEN
drop obj: self true ;m
:m NEWOBJ: ¥ ( ^class -- )
nilH add: super> (PHlist)
newObj: super ;m
:m REMOVEOBJ: ¥ Completely removes the current element.
releaseObj: super remove: super ;m
:m RELEASE:
BEGIN each: self WHILE drop releaseObj: super REPEAT
release: theList
clear: pos clear: size ;m
:m DUMPALL:
nil?: theList if ." (not open)" EXIT THEN
dump: super cr ." current: " get: pos dup 4/ .
cr ." elements: " cr
BEGIN each: self WHILE dump: [] REPEAT
(sel): self ;m
:m PRINTALL:
nil?: theList if ." (not open)" EXIT THEN
get: pos
BEGIN each: self WHILE print: [] cr REPEAT
(sel): self ;m
;class
:class PTRLIST super{ ptr (PHlist) }
;class
¥ ============== Collections ================
¥ Collections are ordered lists with a current size. We implement them by
¥ multiply inheriting the generic (COL) class with the array class of the
¥ appropriate width. We use a few tricks to avoid late binding to self
¥ in loops.
:class (COL) super{ object }
record
{ int SIZE } ¥ # elements in list
:m SIZE: ¥ ( -- cursize ) Returns #elements currently in list
inline{ get: size} get: size ;m
:m CLEAR: ¥ Set to list to null
clear: size clearx: [self] ;m
:m ADD: ¥ ( val -- ) add value to end of list
get: size limit >= ?error 137
get: size to: [self] 1 +: size ;m
:m LAST: ¥ ( -- val ) Returns contents of end of list
get: size dup 0= ?error 136
1- at: [self] ;m
:m REMOVE: { indx ¥ cnt wid addr -- } ¥ Removes the element at index
get: size indx - 1- -> cnt
cnt 0< ?error 136
width: [self] -> wid
indx ^elem: [self] -> addr
1 -: size
cnt 0exit
addr wid + addr cnt wid * move ;m
:m INDEXOF: { val ¥ ^self ^getelem wid addr -- indx T | -- F }
¥ Finds a value in a collection.
self bind_with getelem: -> ^getelem -> ^self
width: [self] -> wid idxbase -> addr
false get: size 0
?do
addr ^self ^getelem ex-method
val = if drop i true leave then
wid ++> addr
loop ;m
:m PRINT:
get: size 0 ?do i at: [self] cr . loop ;m
:m DUMP:
dump: super ." size: " get: size . ;m
;class
¥ Ordered-Collection is a collection of 4-byte cells.
:class ORDERED-COL super{ (col) array }
;class ¥ That's all, folks!!
¥ X-COL is a collection of execution tokens.
:class X-COL super{ (col) x-array }
:m REMOVEXT: ¥ ( xt -- )
false -> relocChk? pad reloc! true -> relocChk?
pad @ indexof: self 0EXIT
remove: self ;m
:m PRINT:
get: size printNXts: self ;m
;class
:class DIC-MARK super{ object }
#threads array LINKS
record { int CURRENT }
private
:m SETC: { ¥ addr index -- index }
0 -> addr 0 -> index
#threads FOR
i at: links dup addr u>
IF -> addr i -> index ELSE drop THEN
NEXT
index put: current ;m
public
:m CURRENT:
get: current at: links ;m
:m SET: { addr -- }
#threads FOR
context i 2 << + displace
BEGIN dup addr u> ¥ We're 32-bit clean around here!
WHILE displace
REPEAT
i to: links
NEXT
setc: self ;m
:m SETTOTOP: big# set: self ;m
:m NEXT: { ¥ lfa -- lfa }
get: current at: links
dup -> lfa dup 0EXIT
displace get: current to: links
setc: self lfa ;m
;class
dic-mark TheMARK
¥ ========== Resource support ===========
:class RESOURCE super{ handle }
record
{ var RESTYPE
int ID
}
:m SET: ¥ ( type id# -- )
put: ID put: resType ;m
:m GETNEW:
get: resType get: ID getRes dup
NIF ¥ Failed - display type and ID
cr addr: resType 4 type 2 spaces
get: ID . 170 die ¥ Couldn't find this resource
THEN
put: super ;m
:m GETXSTR: { idx ¥ addr -- addr len }
getnew: self
ptr: self -> addr
addr w@ 1- idx min -> idx
2 ++> addr
idx 0 ?DO addr count + -> addr LOOP
addr count ;m
;class
¥ ====================================
¥ SOME UTILITY WORDS
¥ ====================================
¥ Any special run-time initialization can be done conveniently by adding
¥ the appropriate words to the x-col INIT_ACTIONS. These words will be
¥ executed on startup via EXTRA_INITS, right after OBJINIT.
8 x-col INIT_ACTIONS
: X size: init_actions 0 ?DO i exec: init_actions LOOP ;
' x -> extra_inits
: SCREENBITS ¥ ( -- l t r b )
¥ Gets dimension coordinates of host machine's display.
$ 904 @ @ 116 - ¥ **** warning - low mem global ref'd
dup @ unpack
rot 4+ @ unpack ;
: CHKKEY
cr type# 189 ¥ "paused - <space> to continue..."
cr ¥ 01Feb94 DBH Add cr. Better for TW.
(key) cr 0 -> out bl = nif cr decimal abort then ;
: ?P
sleepticks 0 -> sleepticks
?terminal
swap -> sleepticks
NIF pause EXIT THEN ¥ No key hit - just do default PAUSE
(key) drop chkKey ;
: P
sleepticks 0 -> sleepticks
?terminal drop
-> sleepticks ;
' p -> pause ¥ This will be improved when Events is loaded
' ?p -> ?pause
: WORDS { ¥ svbase svcurs n -- }
setToTop: theMark 0 -> out 0 -> n
base -> svbase hex curs -> svcurs -curs cr
BEGIN
next: theMark
?dup
WHILE
1 ++> n
out 60 >
if cr 0 -> out ?pause then
link> dup 6 .r 2 spaces .id space
20 out 20 mod - spaces
REPEAT
svbase -> base
cr ." No of words: " n . cr
svcurs -> curs ;
false value ENDTRAV? ¥ May be set from within a trav handler
¥ to terminate the trav
: (TRAV) { theWord parm -- }
false -> endTrav?
BEGIN
next: theMark
?dup 0EXIT
link> parm theWord execute
endTrav?
UNTIL ;
: TRAV ¥ ( xt parm -- )
¥ Traverses the dictionary, passing each xt and the parm
¥ to the passed-in proc.
setToTop: theMark (trav) ;
: TRAV-FROM ¥ ( xt parm addr -- )
¥ As for TRAV, but starts from the first word whose lfa is
¥ below or at the given address.
set: theMark (trav) ;
¥ =============== Dump ==================
¥ This used to be in the Util module. But sometimes the loading of that
¥ module could cause the address of what we wanted to dump to change.
0 value DUMPADDR
0 value DUMPLEN
: U.R
>r 0 <# #s #> r> over - spaces type ;
: dot4 0 <# # # # # #> type space ;
: D.4 ( addr len -- ) bounds do i w@ dot4 2 +loop ;
: EMIT. ¥ ( c -- )
127 and bl 126 within? nif drop & . then emit ;
: DLN ¥ ( addr -- )
cr dup 8 u.r 2 spaces
dup ( addr ) 8 2dup d.4 space + 8 d.4 space
16 bounds DO i c@ emit. LOOP ;
: ?.N ¥ ( n1 n2 -- n1 )
2dup = if ." ¥/" drop else 1 .r space then ;
: ?.A ¥ ( n1 n2 -- n1 )
2dup = if drop & V emit else 1 .r then ;
: .HEAD ¥ ( addr len -- addr' len' )
swap dup -16 and swap 15 and cr 10 spaces
8 0 DO i ?.n i 1+ ?.n space 2 +LOOP space
16 8 DO i ?.n i 1+ ?.n space 2 +LOOP space
16 0 DO i ?.a LOOP rot + ;
:f DUMP { addr len ¥ svBase svCurs -- }
base -> svBase hex curs -> svCurs -curs
addr len .head
2dup -> dumpLen -> dumpAddr ¥ Save for DN
bounds DO i dln ?pause 16 +LOOP cr
svbase -> base svCurs -> curs ;f
: DN ¥ Dump next
dumpLen ++> dumpAddr dumpAddr dumpLen dump ;
: .W ' >name 200 dump ;
<" String
¥ Testing:
4 handlearray hh
key!
+echo
:class HAHA super{ object }
public
record
{ var v1
int i1
uint i2
}
:m test: $ 99 put: v1 $ 88 put: i1 $ 77 put: i2 ;m
:m print: print: v1 print: i1 print: i2 cr ;m
:m classinit: 1 put: v1 2 put: i1 3 put: i2 ;m
;class
:class VArr super{ haha large_obj_array }
:m test1: $ 55 put: v1 $ 44 put: i1 $ 33 put: i2 ;m
:m test2: db test: super test1: self ;m
;class
6 varr OA
key!
handleList HL
key!
: h1 ." hello" ;
: h2 ." hi there!" ;
3 x-array xx
xts{ h1 h2 h1 } put: xx